#ifndef QT_NO_OPENGL
#include <QtOpenGL>
#endif

#include "DopplerGraphicview.h"
#include "DopplerDrawScan.h"
#include "DopplerGateItem.h"
#include <QPrintDialog>
#include <QPrinter>
#include <qmath.h>
#include <QImage>
#include <QGraphicsScene>
#include <QGraphicsWidget>
#include <QTimer>


#define DPL_BASE_IMAGE_FORMATE     (QImage::Format_RGB888)
#define FLOAT_GATE                 0.00001
#define FLOAT_EQ(a, b)             (fabs(a - b) < 0.00001)

class GraphicsViewBase:public QGraphicsWidget
{
public:
    GraphicsViewBase(QGraphicsItem *parent = 0 , QSize cSize_ = QSize(100 , 100))
        : QGraphicsWidget(parent)
    {
        setWindowFlags(Qt::Window | Qt::CustomizeWindowHint
                                     | Qt::WindowTitleHint | Qt::FramelessWindowHint);
        m_cSize = cSize_ ;
        if(m_cSize.width() * m_cSize.height())
            m_pImage = new QImage(m_cSize , DPL_BASE_IMAGE_FORMATE) ;
        else
            m_pImage = NULL ;

        setZValue(1);
    }

    ~GraphicsViewBase()
    {
        delete m_pImage;
    }

    void SetBaseImage(QImage* pImage_)
    {
        m_pImage = pImage_ ;
    }

    void SetBaseImageSize(QSize& size_)
    {
        m_cSize = size_  ;
        ResetBaseImage()  ;
    }

    QImage* GetBaseImage()
    {
        return m_pImage;
    }

    void ResetBaseImage()
    {
        if(m_pImage) delete m_pImage ;
        m_pImage = new QImage(m_cSize , DPL_BASE_IMAGE_FORMATE) ;
    }

    void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget * = 0)
    {
        if(m_pImage)
            painter->drawImage(QRect(0 , 0 , m_cSize.width() , m_cSize.height()), *m_pImage);
    }
private:
    QImage* m_pImage ;
    QSize   m_cSize  ;

};


DopplerGraphicView::DopplerGraphicView(QWidget *parent , QSize size_) :
    QGraphicsView(parent)
{
    // disable scroll bar
    setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    //****************************************************
    // inittialize this view
    setFixedSize(size_);
    setRenderHint(QPainter::Antialiasing, true);
    setDragMode(QGraphicsView::RubberBandDrag);
    setOptimizationFlags(QGraphicsView::DontSavePainterState);
    setViewportUpdateMode(QGraphicsView::SmartViewportUpdate);

    //setFocusPolicy( Qt::ClickFocus);
    // use openGL to render drawing
    EnableRenderOpenGL(true) ;

    m_pDrawScan   = NULL ;
    m_pScene      = NULL ;
    m_pBackGround = NULL ;
    m_nScaleH = 1.0 ;
    m_nScaleV = 1.0 ;
    InitGraphicView(size());

    m_pDrawScan = NULL ; //new DplDrawAscanH(m_pBackGround->GetBaseImage());
    //****************************************************
}


DopplerGraphicView::~DopplerGraphicView()
{
    delete   m_pBackGround    ;
    delete   m_pScene;        ;
    delete   m_pDrawScan      ;
}


void DopplerGraphicView::InitGraphicView(const QSize& cSize_)
{
    QRect cRect(0 , 0 , cSize_.width() , cSize_.height()) ;
    if(!m_pScene)
    {
        m_pScene = new QGraphicsScene();
        m_pScene->setItemIndexMethod(QGraphicsScene::NoIndex);
        setScene(m_pScene);
    }
    this->setSceneRect(cRect);
    if(m_pBackGround) delete m_pBackGround ;
    m_pBackGround = new GraphicsViewBase(0, cSize_);
    m_pBackGround->setGeometry(cRect);
    m_pScene->addItem(m_pBackGround);
}

void DopplerGraphicView::slotResetView()
{
    SetupMatrixScale(1.0 , 1.0 );
    ensureVisible(QRectF(0 , 0 , 0 , 0));
}

void DopplerGraphicView::SetupMatrixScale(double nScaleH_ , double nScaleV_)
{
    m_nScaleH = nScaleH_ ; m_nScaleV = nScaleV_ ;
    QMatrix matrix;
    matrix.scale(nScaleH_ , nScaleV_ );
    setMatrix(matrix);
    GeometryChanged() ;
}

void DopplerGraphicView::slotPrint()
{
#ifndef QT_NO_PRINTER
    QPrinter printer;
    QPrintDialog dialog(&printer, this);
    if (dialog.exec() == QDialog::Accepted) {
        QPainter painter(&printer);
        render(&painter);
    }
#endif
}

void DopplerGraphicView::wheelEvent ( QWheelEvent * event )
{
    int numDegrees = event->delta() / 8;
    int numSteps = numDegrees / 15;

    m_nScaleH += numSteps / 10.0 ;
    m_nScaleV += numSteps / 10.0 ;

    if(m_nScaleH < 1) {m_nScaleV = m_nScaleH = 1 ;}
    if(m_nScaleH > 10) {m_nScaleV = m_nScaleH = 10 ;}
    centerOn(event->pos());
    SetupMatrixScale( m_nScaleH , m_nScaleV ) ;
}

void DopplerGraphicView::resizeEvent(QResizeEvent *event)
{
    QGraphicsView::resizeEvent(event);
}

void DopplerGraphicView::SetDrawOperation(DopplerDrawScan* pDrawScan_)
{
    m_pDrawScan = pDrawScan_ ;
}

void DopplerGraphicView::mousePressEvent(QMouseEvent *event)
{
    if(Qt::LeftButton == event->button())
    {
        m_cPosStart = event->pos() ;
    }
    else if (Qt::RightButton == event->button())
    {
        slotResetView();
    }
    QGraphicsView::mousePressEvent(event) ;

    if(m_pScene->selectedItems().isEmpty())
        m_bItemSelected = 0  ;
    else
        m_bItemSelected = 1  ;
}

void DopplerGraphicView::mouseMoveEvent(QMouseEvent *event)
{
    QGraphicsView::mouseMoveEvent(event) ;
}


void DopplerGraphicView::mouseReleaseEvent(QMouseEvent *event)
{
    if(!m_bItemSelected)
    {
        if(Qt::LeftButton == event->button())
        {
            if(FLOAT_EQ(m_nScaleH , 1) && FLOAT_EQ(m_nScaleH , 1))
            {
                m_cPosStop = event->pos() ;
                QRect rect(m_cPosStart , m_cPosStop) ;
                m_cZoomRect = rect ;
                zoomAction();
            }
        }
    }
    QGraphicsView::mouseReleaseEvent(event) ;
}

void DopplerGraphicView::zoomAction()
{
    if(abs(m_cZoomRect.height()) > 50 && abs(m_cZoomRect.width()) > 50 )
    {
        QSize _size = size();
        double _nScaleX = ((double)_size.width()) / m_cZoomRect.width() ;
        double _nScaleY =  ((double)_size.height()) / m_cZoomRect.height() ;
        _nScaleX = ((int)(_nScaleX * 100 )) / 100.0  ;
        _nScaleY = ((int)(_nScaleY * 100 )) / 100.0  ;

        centerOn(m_cZoomRect.center());
        SetupMatrixScale(fabs(_nScaleX) , fabs(_nScaleY));
    }
}

void DopplerGraphicView::EnableRenderOpenGL(bool bEnable_)
{
#ifdef QT_OPENGL_LIB
    if(bEnable_)
        setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));
    else
#endif
        setViewport(new QWidget);
}

void DopplerGraphicView::SetBackgroundBrush(const QColor& color)
{
    QImage* pImage = m_pBackGround->GetBaseImage() ;
    QPainter painter(pImage);
    painter.fillRect(pImage->rect() , color);
}


void DopplerGraphicView::GeometryChanged()
{
    QPolygonF _rect    = mapToScene (rect()) ;
    QRectF  rectDisplay = _rect.boundingRect();
    QRectF  rangeDisplay  = RangeTranslate(rectDisplay)  ;
    emit signalViewChanged(rangeDisplay)  ;
}

QRectF DopplerGraphicView::RangeTranslate(QRectF& rect_)
{
    QRectF scene = sceneRect() ;
    double _nSceneWidth = scene.width() , _nSceneHeight = scene.height() ;

    double _nStartX , _nStopX, _nStartY , _nStopY ;
    _nStartX = rect_.left() / _nSceneWidth  ;
    _nStopX  = rect_.right() / _nSceneWidth ;

    _nStartY = rect_.top() / _nSceneHeight  ;
    _nStopY  = rect_.bottom() / _nSceneHeight  ;

    _nStartX = ((int) (_nStartX * 100)) / 100.0 ;
    _nStopX  = ((int) (_nStopX  * 100)) / 100.0 ;
    _nStartY = ((int) (_nStartY * 100)) / 100.0 ;
    _nStopY  = ((int) (_nStopY  * 100)) / 100.0 ;
    //qDebug("%f %f %f %f" , _nStartX , _nStartY , _nStopX - _nStartX ,  _nStopY - _nStartY  );
    return QRectF( _nStartX , _nStartY , _nStopX - _nStartX ,  _nStopY - _nStartY )  ;
}


void DopplerGraphicView::AddOverlayItems(QGraphicsItem* item_)
{
    if(item_)
        m_pScene->addItem(item_);
}

QSize DopplerGraphicView::GetSceneSize()
{
    QRectF _rect = m_pScene->sceneRect() ;
    QSize _size(_rect.width() , _rect.height())  ;
    return _size  ;
}

void DopplerGraphicView::SetDrawScan(DopplerDrawScan*  pDrawScan_)
{
    m_pDrawScan = pDrawScan_  ;
    pDrawScan_->SetDrawBuff(m_pBackGround->GetBaseImage()) ;
    connect( m_pDrawScan , SIGNAL(signalUpdateDrawing()) ,this ,  SLOT(slotUpdateDrawing()) )  ;
}

void DopplerGraphicView::slotUpdateDrawing()
{
    m_pBackGround->update();
}
